package main

import (
	"errors"
	"fmt"
	"sync"
)

func main() {
	bank := Bank{balance: map[string]float64{
		"a": 10000,
		"b": 20000,
	}}
	wait1 := sync.WaitGroup{}
	wait1.Add(40000)
	for i := 0; i < 10000; i++ {
		go func() {
			bank.In("a", 2)
			wait1.Done()
		}()
	}
	for i := 0; i < 10000; i++ {
		go func() {
			err := bank.Out("a", 1)
			if err != nil {
				panic(err)
			}
			wait1.Done()
		}()
	}

	for i := 0; i < 10000; i++ {
		go func() {
			err := bank.Out("b", 2)
			if err != nil {
				panic(err)
			}
			wait1.Done()
		}()
	}
	for i := 0; i < 10000; i++ {
		go func() {
			bank.In("b", 2)
			wait1.Done()
		}()
	}
	wait1.Wait()
	fmt.Println(bank.balance["a"], bank.balance["b"])

}

type Bank struct {
	sync.Mutex
	balance map[string]float64
}

// In 收入
func (b *Bank) In(account string, value float64) {
	// 加锁 保证同一时间只有一个协程能访问这段代码
	b.Lock()
	defer b.Unlock()

	if _, ok := b.balance[account]; !ok {
		b.balance[account] = 0.0
	}

	b.balance[account] += value
}

// Out 支出
func (b *Bank) Out(account string, value float64) error {
	// 加锁 保证同一时间只有一个协程能访问这段代码
	b.Lock()
	defer b.Unlock()

	v, ok := b.balance[account]
	if !ok || v < value {
		return errors.New("account not enough balance")
	}

	b.balance[account] -= value
	return nil
}
